﻿
using NLog;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace EpubFactory.Common
{
    public class HttpService
    {
        const string UserAgent = "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0";
        private static readonly Func<HttpClient> clientFactory = () =>
        {
            var client = new HttpClient();
            //client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ApplicationSetting.Token);
            return client;

        };
        private static readonly ObjectPool<HttpClient> Pool = new ObjectPool<HttpClient>(clientFactory);
        protected static readonly Logger _log = LogManager.GetLogger("http", typeof(HttpService));

        public virtual string BaseUrl { get; protected set; }

        public HttpService()
        {
            //BaseUrl = ApplicationSetting.ApiBaseUrl;
        }

        public static HttpClient GetHttpClient(string userAgent = null, string referer = null, bool allowAutoRedirect = false)
        {
            var client = new HttpClient(new HttpClientHandler()
            {
                AllowAutoRedirect = allowAutoRedirect
            });
            if (!string.IsNullOrWhiteSpace(userAgent))
            {
                client.DefaultRequestHeaders.Add("UserAgent", userAgent);
            }
            else
            {
                client.DefaultRequestHeaders.Add("UserAgent", UserAgent);
            }
            if (!string.IsNullOrWhiteSpace(referer))
            {
                client.DefaultRequestHeaders.Add("Referer", "http://www.99lib.net");
            }
            return client;
        }
        protected HttpClient GetPoolHttpClient()
        {
            var client = Pool.GetObject();
            return client;
        }
        protected HttpClient GetHttpClient()
        {
            return clientFactory();
        }
        protected void CommonHandle(CommonResult result)
        {
            if (result != null)
            {
                //if (result.errorCode.Equals("108"))
                //{
                //    throw new InvalidRequestException(401, "Ticket失效");
                //}
                if (result.Code.Equals(ResultCode.Ok))
                {

                }
                else
                {
                    // TODO: throw ex
                }
            }
        }

        protected CommonResult<T> Get<T>(string url, NameValueCollection query)
        {

            url = BaseUrl + url;
            var client = GetPoolHttpClient();

            _log.Debug("url:{1},query:{0}", JsonHelper.Serialize(query), url);
            string content = null;
            if (query != null)
            {
                var queryString = NameValueCollectionToString(query);
                content =
                    client.GetStringAsync(url + "?" + queryString).Result;
            }
            else
            {
                content = client.GetStringAsync(url).Result;
            }
            _log.Debug("url:{1},result:{0}", content, url);
            var result = JsonHelper.Deserialize<CommonResult<T>>(content);
            Pool.PutObject(client);
            CommonHandle(result);
            return result;
        }
        protected CommonResult<T> Get<T>(string url, IDictionary<string, string> query = null)
        {
            url = BaseUrl + url;
            var client = GetPoolHttpClient();

            _log.Debug("url:{1},query:{0}", JsonHelper.Serialize(query), url);
            string content = null;
            if (query != null)
            {
                var queryString = DictionaryToQueryString(query);
                content =
                    client.GetStringAsync(url + "?" + queryString).Result;
            }
            else
            {
                content = client.GetStringAsync(url).Result;
            }
            _log.Debug("url:{1},result:{0}", content, url);
            var result = JsonHelper.Deserialize<CommonResult<T>>(content);

            Pool.PutObject(client);
            CommonHandle(result);
            return result;
        }
        protected CommonResult<T> Post<T>(string url, IDictionary<string, string> form)
        {
            url = BaseUrl + url;
            var client = GetPoolHttpClient();

            _log.Debug("url:{1},param:{0}", JsonHelper.Serialize(form), url);
            var response =
               client.PostAsync(url, new FormUrlEncodedContent(form)).Result;
            response.EnsureSuccessStatusCode();
            var content = response.Content.ReadAsStringAsync().Result;
            _log.Debug("url:{1},result:{0}", content, url);
            var result = JsonHelper.Deserialize<CommonResult<T>>(content);
            Pool.PutObject(client);
            CommonHandle(result);
            return result;
        }
        protected CommonResult<T> Post<T>(string url, HttpContent httpContent)
        {
            url = BaseUrl + url;
            var client = GetPoolHttpClient();

            _log.Debug("url:{1},httpContent:{0}", JsonHelper.Serialize(httpContent), url);
            var response =
               client.PostAsync(url, httpContent).Result;
            response.EnsureSuccessStatusCode();
            var content = response.Content.ReadAsStringAsync().Result;
            _log.Debug("url:{1},result:{0}", content, url);
            var result = JsonHelper.Deserialize<CommonResult<T>>(content);
            Pool.PutObject(client);
            CommonHandle(result);
            return result;
        }
        protected static string NameValueCollectionToString(NameValueCollection param)
        {
            return string.Join("&", param.AllKeys.Select(item => string.Format("{0}={1}", HttpUtility.UrlEncode(item), HttpUtility.UrlEncode(param[item]))));
        }
        protected static string DictionaryToQueryString(IDictionary<string, string> param)
        {
            return string.Join("&",
                param.Select(s => string.Format("{0}={1}", HttpUtility.UrlEncode(s.Key), HttpUtility.UrlEncode(s.Value))));
        }
    }
    public class CommonResult
    {
        public ResultCode Code { get; set; }
        public string Message { get; set; }
    }
    public class CommonResult<T> : CommonResult
    {

        public T Model { get; set; }
    }
    public enum ResultCode
    {
        Ok = 200,
        Fail = 400,
        Exception = 500
    }
}
